<?php
declare(strict_types=1);

namespace app\Services;

use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Core\OssUtil;


class UploadFileService
{
    /**
     * 获取OSS配置数据
     * @return array
     */
    private function ossConfig()
    {
        return [
            'accessId' => env('OSS_ACCESS_ID', ''),
            'accessKey' => env('OSS_ACCESS_KEY', ''),
            'endpoint' => env('OSS_ENDPOINT', 'https://oss-cn-hangzhou.aliyuncs.com'),
            'bucket' => env('OSS_BUCKET', 'wmm-cxtt')
        ];
    }

    /**
     * 上传文件到阿里云
     * @param $file
     * @param array $type
     * @return array
     */
    public function ossUpload($file, $type)
    {
        try {
            if ($file["file"]["error"] == 0) {
                if ($type == 'img') {
                    return self::uploadImg($file);
                } else {
                    return self::uploadFile($file);
                }
            }

            return hello_error('文件不能为空！');

        } catch (\Exception $exception) {
            return hello_error('失败！', $exception->getMessage());
        }

    }

    /**
     * 上传图片到阿里云
     * @param $file
     * @return array
     */
    public function uploadImg($file)
    {
        try {
            if ($file['size'] > 10485760) {
                return hello_error('上传的图片不能大于10MB');
            }
            $pixel = getimagesize($file['tmp_name']);//获取图片大小
            $suffix = explode('.', $file['name']);
            $pathName = 'admin/imgs/' . date('Y-m') . '/' . uniqid() . '.' . $suffix[1]; //生成文件名
            $filePath = $file['tmp_name']; //临时文件路径

            $config = self::ossConfig();
            $ossClient = new OssClient($config['accessId'], $config['accessKey'], $config['endpoint']);
            $options = array(OssClient::OSS_CONTENT_TYPE => 'image/jpg');
            $result = $ossClient->uploadFile($config['bucket'], $pathName, $filePath, $options);

            if ($result['info']) {
                $resData = [
                    'url' => $result['oss-request-url'],
                    'src' => $pathName . '?w=' . $pixel[0] . '&h=' . $pixel[1]
                ];
                return hello_success('上传成功', $resData);
            }

            return hello_error('上传失败！');

        } catch (\Exception $exception) {
            return hello_error('失败！', $exception->getMessage());
        }
    }

    /**
     * 富文本编辑器上传文件到阿里云
     * @param $file
     * @param $fileName
     * @return array
     */
    public function uedUploadFile($file, $fileName)
    {
        try {
            if ($file['size'] > 10485760) {
                return hello_error('上传的图片不能大于10MB');
            }

            $pathName = 'men_hu/ueditor/' . date('Y-m') . '/' . $fileName; //生成文件名
            $filePath = $file['tmp_name']; //临时文件路基

            $config = self::ossConfig();
            $ossClient = new OssClient($config['accessId'], $config['accessKey'], $config['endpoint']);
            $options = array(OssClient::OSS_CONTENT_TYPE => 'image/jpg');
            $result = $ossClient->uploadFile($config['bucket'], $pathName, $filePath, $options);

            if ($result['info']) {
                $resData = ['src' => $pathName, 'url' => $result['info']['url']];
                return hello_success('上传成功', $resData);
            }

            return hello_error('上传失败！');

        } catch (\Exception $exception) {
            return hello_error('失败！', $exception->getMessage());
        }
    }

    /**
     * 上传文件到阿里云
     * @param $file
     * @return array
     */
    public function uploadFile($file)
    {
        try {
            if ($file['size'] > 31457280) {
                return hello_error('上传的文件不能大于30MB');
            }

            $suffix = explode('.', $file['name']);
            $pathName = 'admin/files/' . date('Y-m') . '/' . uniqid() . '.' . $suffix[1]; //生成文件名
            $filePath = $file['tmp_name']; //临时文件路基

            $config = self::ossConfig();
            $ossClient = new OssClient($config['accessId'], $config['accessKey'], $config['endpoint']);
            $result = $ossClient->uploadFile($config['bucket'], $pathName, $filePath);

            if ($result['info']) {
                $resData = ['src' => $pathName, 'url' => $result['info']['url'], 'size' => $file['size']];
                return hello_success('上传成功', $resData);
            }

            return hello_error('上传失败！');

        } catch (\Exception $exception) {
            return hello_error('失败！', $exception->getMessage());
        }
    }

    /**
     * 文件分片上传
     * @param $file
     * @return array
     */
    public function uploadFileByPiece($file)
    {
        try {
            $suffix = explode('.', $file['name']);
            $pathName = 'men_hu/files/' . date('Y-m') . '/' . uniqid() . '.' . $suffix[1]; //生成文件名
            $uploadFile = $file['tmp_name']; //临时文件路基

            //步骤1：初始化一个分片上传事件，获取uploadId。
            $config = self::ossConfig();
            $ossClient = new OssClient($config['accessId'], $config['accessKey'], $config['endpoint']);
            $uploadId = $ossClient->initiateMultipartUpload($config['bucket'], $pathName);

            //步骤2：上传分片。
            $partSize = 10 * 1024 * 1024;//一片10M
            $uploadFileSize = filesize($uploadFile);
            $pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
            $responseUploadPart = array();
            $uploadPosition = 0;
            $isCheckMd5 = true;
            foreach ($pieces as $i => $piece) {
                $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
                $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
                $upOptions = array(
                    // 上传文件。
                    $ossClient::OSS_FILE_UPLOAD => $uploadFile,
                    // 设置分片号。
                    $ossClient::OSS_PART_NUM => ($i + 1),
                    // 指定分片上传起始位置。
                    $ossClient::OSS_SEEK_TO => $fromPos,
                    // 指定文件长度。
                    $ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
                    // 是否开启MD5校验，true为开启。
                    $ossClient::OSS_CHECK_MD5 => $isCheckMd5,
                );
                // 开启MD5校验。
                if ($isCheckMd5) {
                    $contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
                    $upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
                }
                try {
                    // 上传分片。
                    $responseUploadPart[] = $ossClient->uploadPart($config['bucket'], $pathName, $uploadId, $upOptions);
                } catch (OssException $e) {
                    printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
                    printf($e->getMessage() . "\n");
                    return;
                }
                printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} OK\n");
            }
            // $uploadParts是由每个分片的ETag和分片号（PartNumber）组成的数组。
            $uploadParts = array();
            foreach ($responseUploadPart as $i => $eTag) {
                $uploadParts[] = array(
                    'PartNumber' => ($i + 1),
                    'ETag' => $eTag,
                );
            }

            //步骤3：完成上传。
            // 执行completeMultipartUpload操作时，需要提供所有有效的$uploadParts。OSS收到提交的$uploadParts后，会逐一验证每个分片的有效性。当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
            $result = $ossClient->completeMultipartUpload($config['bucket'], $pathName, $uploadId, $uploadParts);

            if ($result['info']) {
                $url = explode('?', $result['info']['url']);
                $resData = ['src' => $pathName, 'url' => $url[0]];
                return hello_success('上传成功', $resData);
            }

            return hello_error('上传失败！');
        } catch (\Exception $exception) {
            return hello_error('失败！', $exception->getMessage());
        }

    }

    /**
     * 删除OSS上指定文件
     * @param string $fileName
     * @return array
     */
    function ossDelete($fileName = '')
    {
        try {
            if (empty($fileName)) {
                return hello_error('需要删除的文件名不能为空！');
            }

            $config = self::ossConfig();
            $ossClient = new OssClient($config['accessId'], $config['accessKey'], $config['endpoint']);

            if ($ossClient->doesObjectExist($config['bucket'], $fileName)) {
                $ossClient->deleteObject($config['bucket'], $fileName);
                return hello_success('删除成功!');
            } else {
                return hello_error('图片不存在！');
            }
        } catch (\Exception $exception) {
            return hello_error($exception->getMessage());
        }
    }
}
